package org.anno.chunkdb;

import com.google.protobuf.CodedInputStream;
import com.google.common.base.Predicate;

import org.anno.chunkdb.Metadata.Column.Type;

/**
 * Visitor interface with do-nothing method implementations for receiving the value of a cell.
 */
public class TypedCellVisitor {

  public void visitString(byte[] buf, int offset, int len) {
  }

  public void visitDouble(double v) {
  }

  public void visitLong(long v) {
  }

  /**
   * Base class for a visitor that makes a boolean decision based on the typed cell value.
   */
  public static class CellPredicateVisitor extends TypedCellVisitor {

    public static CellPredicateVisitor from(final Predicate<CodedInputStream> p) {
      return new CellPredicateVisitor() {
        public void visitString(byte[] buf, int offset, int len) {
          included = p.apply(CodedInputStream.newInstance(buf, offset, len));
        }
      };
    }

    /**
     * Set by the visit* calls.
     */
    protected boolean included;

    /**
     * Returns a {@link Predicate} for rows, whose cell value at the given column ID and type is
     * included by this {@link CellPredicateVisitor}.
     */
    public Predicate<Host<RowVisitor>> asRowPredicate(final int column, final Type filteredType) {
      RowVisitor rowPredicateVisitor = new RowVisitor() {
        public void visit(int columnIndex, Type type, Host<TypedCellVisitor> cell) {
          if (columnIndex == column && type == filteredType) {
            cell.accept(CellPredicateVisitor.this);
          }
        }
      };
      return row -> {
        row.accept(rowPredicateVisitor);
        return included;
      };
    }
  }
}
